using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

using zeroflag.Windows.Custom;

namespace zeroflag.Parserz.IDE
{
	public class TokenNode : ISelectable
	{
		public TokenNode(TokenController viewController)
		{
			this.Configuration = viewController;
		}

		public TokenNode(TokenController viewController, TokenNode parent)
			: this(viewController)
		{
			this.Parent = parent;
		}

		public TokenNode(TokenController viewController, TokenNode parent, TokenNode left)
			: this(viewController, parent)
		{
			this.Left = left;
		}

		public TokenNode(TokenController viewController, TokenNode parent, TokenNode left, Token token)
			: this(viewController, parent, left)
		{
			this.Token = token;
		}

		public TokenNode(TokenController viewController, TokenNode parent, Token token)
			: this(viewController, parent)
		{
			this.Token = token;
		}

		public bool Render(zeroflag.Windows.Custom.RenderArea area)
		{
			if (this.Token == null || this.Configuration == null)
				return false;

			Graphics g = area.Graphics;

			Rectangle frame = new Rectangle(this.Location.X, this.Location.Y, this.Width - 1, this.Height - 1);
			g.FillRectangle(this.Colors.BackgroundBrush, frame);
			if (this.Selected)
			{
				g.DrawRectangle(this.Configuration.PenSelected, frame);
			}
			else
			{
				g.DrawRectangle(this.Colors.FramePen, frame);
			}

			g.DrawString(this.Text, this.Configuration.Font, this.Colors.TextBrush, this.TextLocation);

			area.Include(this.Region);

			if (this.Child != null)
				this.Child.Render(area);

			if (this.Right != null)
				this.Right.Render(area);

			return true;
		}


		#region Properties
		private Token m_Token;
		private TokenController m_Configuration;
		TokenNode m_Parent;
		TokenNode m_Left;
		TokenNode m_Child;
		TokenNode m_Right;
		bool m_Selected = false;
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		[System.ComponentModel.ReadOnly(true)]
		public bool Selected
		{
			get { return m_Selected; }
			set
			{
				m_Selected = value;
				if (value)
				{
					// add to selecteditems collection...
					if (!this.Configuration.SelectedNodes.Contains(this))
						this.Configuration.SelectedNodes.Add(this);
				}
				else
				{
					// remove from selected items...
					if (this.Configuration.SelectedNodes.Contains(this))
						this.Configuration.SelectedNodes.Remove(this);
				}
			}
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		[System.ComponentModel.ReadOnly(true)]
		public TokenNode Right
		{
			get { return m_Right; }
			set { m_Right = value; }
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public TokenNode Child
		{
			get { return m_Child; }
			set
			{
				m_Child = value;
			}
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public TokenNode Left
		{
			get { return m_Left; }
			set
			{
				m_Left = value;
				m_Location = new Point(-1, -1);
				if (value != null)
					value.Right = this;
			}
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		[System.ComponentModel.ReadOnly(true)]
		public TokenNode Parent
		{
			get { return m_Parent; }
			set
			{
				m_Parent = value;
				m_Location = new Point(-1, -1);
			}
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public ColorCombi Colors
		{
			get
			{
				return this.Configuration[this.Token];
			}
			set
			{
				this.Configuration[this.Token] = value;
			}
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public TokenController Configuration
		{
			get { return m_Configuration; }
			set
			{
				m_Configuration = value;
				m_Location = new Point(-1, -1);
			}
		}


		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public Token Token
		{
			get { return m_Token; }
			set
			{
				if (m_Token != value)
				{
					if (m_Token != null)
					{
						this.Configuration.Nodes.Remove(m_Token);
					}
					m_Token = value;
					m_Width = -1;
					m_Location = new Point(-1, -1);
					if (m_Token != null)
					{
						if (this.Configuration.Nodes.ContainsKey(m_Token))
							this.Configuration.Nodes.Remove(m_Token);
						this.Configuration.Nodes.Add(m_Token, this);

						if (this.Token.Inner != null)
							this.Child = new TokenNode(this.Configuration, this, this, this.Token.Inner);

						if (this.Token.Count > 0)
							this.Right = new TokenNode(this.Configuration, this.Parent, this, this.Token[0]);
					}
				}
			}
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public string Text
		{
			get
			{
				if (this.Token is Character)
					return ((Character)this.Token).Value.ToString().Replace("\n", @"\n").Replace("\r", @"\r").Replace("\t", @"\t  ");
				else
					return "";
			}
		}

		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public Rectangle Region
		{
			get
			{
				return new Rectangle(this.Location, this.Size);
			}
		}


		Point m_Location = new Point(-1, -1);
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		[System.ComponentModel.ReadOnly(true)]
		public Point Location
		{
			get
			{
				if (m_Location.X < 0 || m_Location.Y < 0)
				{
					if (this.Left != null)
					{
						m_Location = this.Left.Location;
						if (this.Left.Token is Character && ((Character)this.Left.Token).Value == '\n')
						{
							m_Location.X = 0;
							m_Location.Y += this.Left.Size.Height;
						}
						else
						{
							m_Location.X += this.Left.Size.Width;
						}
					}
					else if (this.Parent != null)
					{
						m_Location = this.Parent.Location;
					}
					else
					{
						m_Location = new Point(0, 0);
					}
					m_Location = new Point(m_Location.X + this.Padding.Left, m_Location.Y + this.Padding.Left);
				}
				return m_Location;
			}
		}

		[System.ComponentModel.ReadOnly(true)]
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public Point TextLocation
		{
			get
			{
				Point location = this.Location;
				location.X += this.Margin.Left;
				location.Y += this.Margin.Top;
				return location;
			}
			set
			{
				this.Margin = new Padding(value.X - this.Location.X, value.Y - this.Location.Y, this.Margin.Right, this.Margin.Bottom);
			}
		}

		[System.ComponentModel.ReadOnly(true)]
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public Size Size
		{
			get
			{
				return new Size(this.Width, this.Height);
			}
		}

		int m_Width = -1;
		[System.ComponentModel.ReadOnly(true)]
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public int Width
		{
			get
			{
				if (m_Width < 0)
				{
					m_Width = this.Configuration.CharSize.Width * this.Text.Length + this.Padding.Left + this.Padding.Right;
				}
				return m_Width;
			}
		}

		[System.ComponentModel.ReadOnly(true)]
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public int Height
		{
			get
			{
				return this.Configuration.CharSize .Height + this.Padding.Top + this.Padding.Bottom;
			}
		}

		[System.ComponentModel.ReadOnly(true)]
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public Padding Margin
		{
			get { return this.Configuration.Margin; }
			set
			{
				this.Configuration.Margin = value;
				m_Location = new Point(-1, -1);
			}
		}

		[System.ComponentModel.ReadOnly(true)]
		[System.ComponentModel.Browsable(true)]
		[System.ComponentModel.Category("Token")]
		public Padding Padding
		{
			get { return this.Configuration.Padding; }
			set
			{
				this.Configuration.Padding = value;
				m_Location = new Point(-1, -1);
			}
		}


		#endregion Properties

		public virtual TokenNode Find(int x, int y)
		{
			TokenNode found = null;

			if (this.Region.Contains(x, y))
			{
				if (this.Child != null)
					found = this.Child.Find(x, y);
				if (found == null)
					found = this;
			}
			else
			{
				if (this.Right != null)
					found = this.Right.Find(x, y);
			}
			return found;

			//throw new NotImplementedException("TokenNode.Find(x,y)");
		}

		public override string ToString()
		{
			return this.Token.GetType().Name + ": " + this.Text;
		}

		public static implicit operator Token(TokenNode node)
		{
			return node.Token;
		}
	}
}
